package MonteCarloConcurrency;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import GUI.GUI;


public class MonteCarloConcurrency {
	
	public static void main(final String[] args) throws InterruptedException, ExecutionException, NumberFormatException, IOException 
	{

		//System.out.println("arg : "+argu_main[0]);
		GUI gui = null;
		GUI.createAndShowGUI();
	}
	
	public static double MonteCarloStandardOption(String CallPutFlag, double S, double X, double T, double r, double b, double v, int nSteps)
	{
		double dt, St, Sum = 0, Drift, vSqrdt;
		int i,j,z = 0;
		
		dt = T/nSteps;
		Drift = (b - Math.pow(v, 2)/2)*dt;
		vSqrdt = v * Math.sqrt(dt);
		Random rand = new Random();
		
		if(CallPutFlag.equals("c"))
		{
			z = 1;
		}
		else if(CallPutFlag.equals("p"))
		{
			z = -1;
		}
		St = S;
		
		for(j=0;j<nSteps;j++)
		{
			St = St * Math.exp(Drift + vSqrdt * rand.nextGaussian());
		}
		Sum = Sum + Math.max(z*(St-X), 0);

		
		return (Math.exp(-r*T)*(Sum));
	}
	
	public static double[] MonteCarloStandardOptionAVG(final String CallPutFlag,final double S,final double X,final double T,final double r,final double b,final double v,final int nSteps, int nSimulations) throws InterruptedException, ExecutionException
	{
		//mise en place du tableau de retour
		double tab[]=new double[2];
		//D�but du compteur
		final long start = System.nanoTime();
		 //Calcul du nombre de core et tout et tout 
	    final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0.9;
	    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));
	    
	    System.out.println("Number of Cores available is " + numberOfCores);
	    System.out.println("Pool size is " + poolSize);
	    
	    final List<Callable<Double>> partitions = 
	      new ArrayList<Callable<Double>>();
	    
	    for(int i=0;i<nSimulations;i++) {
	      partitions.add(new Callable<Double>() {
	        public Double call() throws Exception {
	          return MonteCarloStandardOption(CallPutFlag, S, X, T, r, b, v, nSteps); 
	        }        
	      });
	    }
	        
	    final ExecutorService executorPool = 
	      Executors.newFixedThreadPool(poolSize); 
	    
	    final List<Future<Double>> values = 
	      executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
	      
	    double result = 0.0; 
	    for(final Future<Double> value : values)  
	      result += value.get(); 

	    executorPool.shutdown();
	    final long end = System.nanoTime();
	    tab[0]=result/nSimulations;
		tab[1]=(end - start)/1.0e9;
		return tab;
	    
	

}

}
